# -*- coding:utf-8 -*-
import json
import re
import time

import requests
from bs4 import BeautifulSoup

from des import DES
import ast
import data
from BullshitGenerator import BullshitGenerator


def timeStamp2date(time_stamp):
    timeArray = time.localtime(time_stamp / 1000)
    otherStyleTime = time.strftime("%Y-%m-%d", timeArray)
    return str(otherStyleTime)


def date2timeStamp(date):
    timeArray = time.strptime(date, "%Y-%m-%d")
    timeStamp = int(time.mktime(timeArray)) * 1000
    return str(timeStamp)


class autoloader:
    def __init__(self, opt):

        self.login_headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,'
                      'application/signed-exchange;v=b3;q=0.9',
            'Accept-Encoding': 'gzip, deflate, br',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 '
        }
        self.from_headers = {
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 ',
        }

        self.post_headers = {
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'text/plain;charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 ',
        }

        self.headers = {
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'application/json;charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 ',
        }

        self.check_headers = {
            'Accept': 'text/html, */*; q=0.01',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'text/html; charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 ',
        }
        self.check_header = {
            'Accept': 'text/plain, */*; q=0.01',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'application/json;charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43 ',
        }

        self.session = requests.Session()
        self.username = ''
        self.password = ''
        self.process_id = ''
        self.form_id = ''
        self.service_id = ''
        self.zb_num_before = 0
        self.zb_num = 0
        self.workflow_id = ''
        self.privilege_id = ''
        self.proc_inst_id = ''
        self.teachers_name = ''
        self.campus_name = ''
        self.preset_data = None
        self.key = ''
        self.reason = ''
        self.startTime = ''
        self.endTime = ''
        self.mst = int(round(time.time() * 1000))
        self.date = ''
        self.specificReasons = ''
        self.set_key(opt)

    def set_key(self, opt):
        self.username = opt.userid
        self.password = opt.password
        self.reason = opt.reason
        self.startTime = opt.startTime
        self.endTime = opt.endTime
        self.date = timeStamp2date(self.mst) if opt.date == '' else opt.date
        if opt.specificReasons == 'Hitokoto':
            self.specificReasons = self.getHitokoto()
        elif opt.specificReasons == 'Bullshit':
            bullshit = BullshitGenerator("data.json", "请假", 100)
            self.specificReasons = bullshit.forward()
        else:
            self.specificReasons = opt.specificReasons

    def getHitokoto(self):
        """
        一言API：https://hitokoto.cn/
        :return:
        """
        session = requests.Session()
        r = session.get('https://v1.hitokoto.cn/?encode=json&c=d&c=i&min_length=18', headers=self.login_headers).text
        r = json.loads(r)
        hitokoto = r.get('hitokoto')
        return hitokoto

    def logIn(self) -> bool:
        r = self.session.get('https://pass.sdu.edu.cn/cas/login', headers=self.login_headers)
        lt = re.findall('id="lt" name="lt" value="(.*?)"', r.text)[0]
        execution = re.findall('name="execution" value="(.*?)"', r.text)[0]
        s = self.username + self.password + lt
        des = DES('1', '2', '3')
        rsa = des.encrypt(s)
        rsa = rsa.upper()
        login_data = {
            'rsa': rsa,
            'ul': len(self.username),
            'pl': len(self.password),
            'lt': lt,
            'execution': execution,
            '_eventId': 'submit'
        }
        self.session.post('https://pass.sdu.edu.cn/cas/login', data=login_data, headers=self.login_headers)
        r1 = self.session.get('https://scenter.sdu.edu.cn/tp_fp/view?m=fp#act=fp/formHome', headers=self.login_headers)
        lt = re.findall('id="lt" name="lt" value="(.*?)"', r1.text)
        if len(lt) != 0:
            return False
        else:
            return True

    def studentServe(self):
        # 切换到学生事务
        AllSvsByConditionPage = {
            "project_id": "1000358707200",
            "category_ids": "",
            "orderBy": "defaultAsc",
            "firstCharacter": "",
            "unit_id": "",
            "isCollect": "all",
            "isRecommend": "no",
            "pageNum": "1",
            "pageSize": "40"
        }
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/formHome/AllSvsByConditionpage',
                              data=json.dumps(AllSvsByConditionPage), headers=self.headers).text
        # 找一下出入信息填报在哪
        items = json.loads(r).get('list')
        for item in items:
            if '学生出入校园信息填报' == item.get('NAME'):
                self.service_id = item.get('COLLECT')
                self.form_id = item.get('FORMID')
                self.process_id = item.get('WORKFLOWTEMPID')
                break

    def zbNumber(self) -> int:
        # 标记一下正在办理的任务数
        payload = {}
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/formHome/allNum', data=json.dumps(payload),
                              headers=self.headers).json()
        return int(r.get('zbNum'))

    def moveTo(self):
        # 转到出入校园信息填报
        r = self.session.get('https://scenter.sdu.edu.cn/tp_fp/visitService?service_id=' + self.service_id,
                             headers=self.login_headers).text

    def check_service(self) -> bool:
        # Fixme:不知道为什么用不了
        r = self.session.get('https://scenter.sdu.edu.cn/tp_fp/fp/serveapply?item_id=undefined',
                             headers=self.check_headers).text
        # 获取服务可用性
        # self.serviceID = {
        #     "serviceID": self.service_id
        # }
        r1 = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/serveapply/checkService',
                               data=json.dumps(self.serviceID),
                               headers=self.check_header).text
        if r != '0':
            return False
        else:
            return True

    def getWorkflowTempID(self):
        self.serviceID = {
            "serviceID": self.service_id
        }
        # 获取工作项编号（应该是叫这个名字
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/serveapply/serveInfo',
                              data=json.dumps(self.serviceID),
                              headers=self.headers).json()
        self.workflow_id = r.get('workflowtempid')

    def getPrivilegeId(self):
        # 获取私有编号（这什么玩意
        getServeApply = {
            "serveID": self.service_id,
            "from": "hall"
        }
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/serveapply/getServeApply',
                              data=json.dumps(getServeApply), headers=self.headers).json()
        self.privilege_id = r.get('privilegeId')

    def getProcInstID(self):
        # 获取流程实例编号
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/serveapply/getContinueService',
                              data=json.dumps(self.serviceID), headers=self.headers).json()
        if len(r) != 0:
            self.proc_inst_id = r[0].get('PROC_INST_ID')

    def getNowPage(self) -> bool:
        # 获取一下当前界面
        r = self.session.get(
            'https://scenter.sdu.edu.cn/tp_fp/formParser?status=select&formid=' + self.form_id + '&service_id=' +
            self.service_id + '&process=' + self.process_id + '&seqId=&seqPid=&SYS_FK=' + self.proc_inst_id +
            '&privilegeId=' + self.privilege_id, headers=self.login_headers)
        soup = BeautifulSoup(r.text, 'lxml')
        databind = soup.body['databind']
        self.teachers_name = soup.find(databind=databind + ".fayxm")['dataprovider']
        self.campus_name = soup.find(databind=databind + ".wcxq")['dataprovider']
        preset_data = soup.find('script', {'id': 'dcstr'}).get_text()
        if preset_data.rfind("privilegeMode") != -1:
            return False
        # 不清楚text/tpl这个模板怎么转json
        preset_data = preset_data.replace('header', '"header"').replace('body :', '"body":')
        preset_data = preset_data.replace('parameters :', '"parameters":').replace('dataStores :', '"dataStores":')
        preset_data = preset_data.replace('name:', '"name":').replace('pageNumber:', '"pageNumber":')
        preset_data = preset_data.replace('pageSize:', '"pageSize":').replace('recordCount:', '"recordCount":')
        preset_data = preset_data.replace('pageSize:', '"pageSize":').replace('recordCount:', '"recordCount":')
        self.preset_data = ast.literal_eval(preset_data.replace('true', '"true"').replace('rowSet:', '"rowSet":'))
        return True

    def editParameters(self):
        # parameters修改
        self.preset_data['body']['parameters']['strUserId'] = ''
        self.preset_data['body']['parameters']['strUserIdCC'] = ''
        self.preset_data['body']['parameters']['nextActId'] = ''

    def getCounsellor(self):
        # 获取辅导员信息
        formParser = {
            'formid': self.form_id,
            'procinstid': self.proc_inst_id,
            'presetbind': self.teachers_name,
            'presetbindtext': '学院辅导员下拉框'
        }
        teachers = self.session.post('https://scenter.sdu.edu.cn/tp_fp/formParser?status=preset', data=formParser,
                                     headers=self.from_headers).text
        teachers = ast.literal_eval(teachers)
        return teachers

    def getCampus(self):
        # 获取校区信息
        formParser = {
            'formid': self.form_id,
            'procinstid': self.proc_inst_id,
            'presetbind': self.campus_name,
            'presetbindtext': '校区中英文(下拉框)'
        }
        campus = self.session.post('https://scenter.sdu.edu.cn/tp_fp/formParser?status=preset', data=formParser,
                                   headers=self.from_headers).text
        campus = ast.literal_eval(campus)
        return campus

    def editDataStores(self):
        # dataStores 修改
        for self.key in self.preset_data['body']['dataStores'].keys():
            if self.key not in ['variable', 'uploader_0']:
                break

        self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['_t'] = 3

        _o = {
            'cxrq': '',
            'CXSJT': '',
            'FXSJT': '',
            'fxrq': ''
        }

        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxrq'] != date2timeStamp(self.date) \
                or self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxrq'] != self.date:
            _o['cxrq'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxrq']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxrq'] = self.date
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJT'] != self.date:
            _o['FXSJT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJT']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJT'] = self.date
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxrq'] != self.date \
                or self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxrq'] != date2timeStamp(
            self.date):
            _o['fxrq'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxrq']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxrq'] = self.date
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJT'] != self.date:
            _o['CXSJT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJT']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJT'] = self.date
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['wcsy'] != self.reason:
            _o['wcsy'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['wcsy']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['wcsy'] = self.reason
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxsj'] != self.startTime:
            _o['cxsj'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxsj']
            _o['cxsj_TEXT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxsj_TEXT']
            _o['CXSJTEXT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJTEXT']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxsj'] = self.startTime
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['cxsj_TEXT'] = self.startTime
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJTEXT'] = self.startTime
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxsj'] != self.endTime:
            _o['fcxsj'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxsj']
            _o['fxsj_TEXT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxsj_TEXT']
            _o['FXSJTEXT'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJTEXT']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxsj'] = self.endTime
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fxsj_TEXT'] = self.endTime
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJTEXT'] = self.endTime
        if self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['jtsyms'] != self.specificReasons:
            _o['jtsyms'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['jtsyms']
            self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['jtsyms'] = self.specificReasons

        self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['_o'] = _o

    def editUploader_0(self):
        # uploader_0 修改
        parameters = {
            'uploader': 'true',
            'exist': 'true',
            'SYS_FK': self.proc_inst_id
        }
        self.preset_data['body']['dataStores']['uploader_0']['parameters'] = parameters
        self.preset_data['body']['dataStores']['uploader_0']['rowSet']['primary'] = [{"_t": 1}]

    def editVariable(self):
        # variable
        for primary in self.preset_data['body']['dataStores']['variable']['rowSet']['primary']:
            if primary['source'] == 'process' and primary['name'] != 'BUSINESS_UNIT':
                primary['_t'] = 1
                if primary['name'] != 'GJXYXS' and primary['name'] != 'PDGQ':
                    primary['_o'] = {"value": ""}
                if primary['name'] == 'CXSJTEXT':
                    primary['value'] = self.startTime
                if primary['name'] == 'WCLX':
                    primary['value'] = '临时外出 Temporary out'
                if primary['name'] == 'FXSJT':
                    primary['value'] = \
                        self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['FXSJT']
                if primary['name'] == 'XM':
                    primary['value'] = \
                        self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['user_name']
                if primary['name'] == 'zts':
                    primary['value'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['zts']
                if primary['name'] == 'FXSJTEXT':
                    primary['value'] = self.endTime
                if primary['name'] == 'CXSJT':
                    primary['value'] = \
                        self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['CXSJT']
                if primary['name'] == 'FDYSH':
                    primary['value'] = \
                        '0,' + self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['fayxm']
                if primary['name'] == 'XQ':
                    primary['value'] = self.preset_data['body']['dataStores'][self.key]['rowSet']['primary'][0]['xqsd']
                if primary['name'] == 'XH':
                    primary['value'] = self.username
                if primary['name'] == 'WCMDD':
                    primary['value'] = '本市 Local city '
                if primary['name'] == 'WCSY':
                    primary['value'] = self.reason
                if primary['name'] == 'SFLX':
                    primary['value'] = '研究生'
            if primary['source'] == 'interface':
                if primary['name'] == 'SYS_DATE':
                    primary['value'] = str(int(round(time.time() * 1000)))
        # print(self.preset_data)

    def postForm(self):
        # 填写表单
        r = self.session.post('https://scenter.sdu.edu.cn/tp_fp/formParser?status=update&formid=' + self.form_id +
                              '&workflowAction=startProcess&seqId=&unitId=&workitemid=&process=' + self.process_id,
                              data=json.dumps(data.student_data), headers=self.post_headers).json()

    def abort(self) -> bool:
        doAbort = {
            'procinst_id': self.proc_inst_id
        }
        abort = self.session.post('https://scenter.sdu.edu.cn/tp_fp/fp/myserviceapply/doAbort',
                                  data=json.dumps(doAbort),
                                  headers=self.headers).text
        if abort == 'true':
            return True
        else:
            return False

    def forward(self):
        if self.logIn():
            self.studentServe()
            self.zb_num_before = self.zbNumber()
            self.moveTo()
            self.getWorkflowTempID()
            self.getPrivilegeId()
            self.getProcInstID()
            if self.getNowPage():
                self.editParameters()
                self.editDataStores()
                self.editUploader_0()
                self.editVariable()
                self.getCampus()
                self.postForm()
                time.sleep(10)
                self.zb_num = self.zbNumber()
            else:
                raise ValueError('至少存在一个申请未被通过')
            if self.zb_num != self.zb_num_before:
                if self.abort():
                    print('检测到申请无法自动通过，已回退')
        else:
            raise ValueError('登录失败！请检查账号和密码是否有误')
